diff: Allow aborting a diff
authorBenjamin Otte <otte@redhat.com>
Sat, 31 Mar 2018 10:52:19 +0000 (12:52 +0200)
committerBenjamin Otte <otte@redhat.com>
Thu, 5 Apr 2018 12:56:38 +0000 (14:56 +0200)
When the max cost for finding a path gets to high, the diff can now be
aborted.

Because render nodes have a fallback method (by just marking the whole
bounds of the nodes as different), we use this to improve performance
of diffs.

This brings fishbowl (which is basically a container node with N images
that change every frame) back to close to previous performance.

gsk/gskdiff.c
gsk/gskdiffprivate.h
gsk/gskrendernodeimpl.c

index 195349609373e2ce5606ab303f19091b44514671..d6390a38088fcdf6e3eba51eeb7a5add0c0d3d77 100644 (file)
@@ -36,6 +36,8 @@ struct _GskDiffSettings {
   GskKeepFunc             keep_func;
   GskDeleteFunc           delete_func;
   GskInsertFunc           insert_func;
+
+  guint allow_abort : 1;
 };
 
 typedef struct _SplitResult {
@@ -61,6 +63,13 @@ gsk_diff_settings_new (GCompareDataFunc compare_func,
   return settings;
 }
 
+void
+gsk_diff_settings_set_allow_abort (GskDiffSettings *settings,
+                                   gboolean         allow_abort)
+{
+  settings->allow_abort = allow_abort;
+}
+
 void
 gsk_diff_settings_free (GskDiffSettings *settings)
 {
@@ -76,7 +85,7 @@ gsk_diff_settings_free (GskDiffSettings *settings)
  * cases using this algorithm is full, so a little bit of heuristic is needed
  * to cut the search and to return a suboptimal point.
  */
-static void
+static GskDiffResult
 split (gconstpointer         *elem1,
        gssize                 off1,
        gssize                 lim1,
@@ -144,7 +153,7 @@ split (gconstpointer         *elem1,
               spl->i1 = i1;
               spl->i2 = i2;
               spl->min_lo = spl->min_hi = 1;
-              return;
+              return GSK_DIFF_OK;
             }
         }
 
@@ -185,7 +194,7 @@ split (gconstpointer         *elem1,
               spl->i1 = i1;
               spl->i2 = i2;
               spl->min_lo = spl->min_hi = 1;
-              return;
+              return GSK_DIFF_OK;
             }
         }
 
@@ -195,7 +204,7 @@ split (gconstpointer         *elem1,
       /*
        * If the edit cost is above the heuristic trigger and if
        * we got a good snake, we sample current diagonals to see
-       * if some of the, have reached an "interesting" path. Our
+       * if some of them have reached an "interesting" path. Our
        * measure is a function of the distance from the diagonal
        * corner (i1 + i2) penalized with the distance from the
        * mid diagonal itself. If this value is above the current
@@ -233,7 +242,7 @@ split (gconstpointer         *elem1,
             {
               spl->min_lo = 1;
               spl->min_hi = 0;
-              return;
+              return GSK_DIFF_OK;
             }
 
           for (best = 0, d = bmax; d >= bmin; d -= 2)
@@ -266,7 +275,7 @@ split (gconstpointer         *elem1,
             {
               spl->min_lo = 0;
               spl->min_hi = 1;
-              return;
+              return GSK_DIFF_OK;
             }
         }
 
@@ -278,6 +287,9 @@ split (gconstpointer         *elem1,
         {
           gssize fbest, fbest1, bbest, bbest1;
 
+          if (settings->allow_abort)
+            return GSK_DIFF_ABORTED;
+
           fbest = fbest1 = -1;
           for (d = fmax; d >= fmin; d -= 2)
             {
@@ -321,7 +333,7 @@ split (gconstpointer         *elem1,
               spl->min_hi = 1;
             }
 
-          return;
+          return GSK_DIFF_OK;
         }
     }
 }
@@ -331,7 +343,7 @@ split (gconstpointer         *elem1,
  * the box splitting function. Note that the real job (marking changed lines)
  * is done in the two boundary reaching checks.
  */
-static void
+static GskDiffResult
 compare (gconstpointer             *elem1,
          gssize                     off1,
          gssize                     lim1,
@@ -384,27 +396,37 @@ compare (gconstpointer             *elem1,
   else
     {
       SplitResult spl = { 0, };
+      GskDiffResult res;
 
       /*
        * Divide ...
        */
-      split (elem1, off1, lim1,
-             elem2, off2, lim2,
-             kvdf, kvdb, need_min,
-             settings, data,
-             &spl);
+      res = split (elem1, off1, lim1,
+                   elem2, off2, lim2,
+                   kvdf, kvdb, need_min,
+                   settings, data,
+                   &spl);
+      if (res != GSK_DIFF_OK)
+        return res;
+
       /*
        * ... et Impera.
        */
-      compare (elem1, off1, spl.i1,
-               elem2, off2, spl.i2,
-               kvdf, kvdb, spl.min_lo,
-               settings, data);
-      compare (elem1, spl.i1, lim1,
-               elem2, spl.i2, lim2,
-               kvdf, kvdb, spl.min_hi,
-               settings, data);
+      res = compare (elem1, off1, spl.i1,
+                     elem2, off2, spl.i2,
+                     kvdf, kvdb, spl.min_lo,
+                     settings, data);
+      if (res != GSK_DIFF_OK)
+        return res;
+      res = compare (elem1, spl.i1, lim1,
+                     elem2, spl.i2, lim2,
+                     kvdf, kvdb, spl.min_hi,
+                     settings, data);
+      if (res != GSK_DIFF_OK)
+        return res;
     }
+
+  return GSK_DIFF_OK;
 }
 
 #if 0
@@ -435,7 +457,7 @@ compare (gconstpointer             *elem1,
   dd2.rindex = xe->xdf2.rindex;
 #endif
 
-void
+GskDiffResult
 gsk_diff (gconstpointer             *elem1,
           gsize                      n1,
           gconstpointer             *elem2,
@@ -445,6 +467,7 @@ gsk_diff (gconstpointer             *elem1,
 {
   gsize ndiags;
   gssize *kvd, *kvdf, *kvdb;
+  GskDiffResult res;
 
   ndiags = n1 + n2 + 3;
 
@@ -454,11 +477,13 @@ gsk_diff (gconstpointer             *elem1,
   kvdf += n2 + 1;
   kvdb += n2 + 1;
 
-  compare (elem1, 0, n1,
-           elem2, 0, n2,
-           kvdf, kvdb, FALSE,
-           settings, data);
+  res = compare (elem1, 0, n1,
+                 elem2, 0, n2,
+                 kvdf, kvdb, FALSE,
+                 settings, data);
 
   g_free (kvd);
+
+  return res;
 }
 
index 240c1c17bd7600546e4903e1e9c6535e6c58549f..9401ad85b22e94528f6fb7ffaf56ed9d925d6215 100644 (file)
 
 G_BEGIN_DECLS
 
+typedef enum {
+  GSK_DIFF_OK = 0,
+  GSK_DIFF_ABORTED,
+} GskDiffResult;
+
 typedef void (* GskKeepFunc)   (gconstpointer elem1, gconstpointer elem2, gpointer data);
 typedef void (* GskDeleteFunc) (gconstpointer elem, gsize idx, gpointer data);
 typedef void (* GskInsertFunc) (gconstpointer elem, gsize idx, gpointer data);
@@ -35,8 +40,10 @@ GskDiffSettings *       gsk_diff_settings_new                   (GCompareDataFun
                                                                  GskDeleteFunc           delete_func,
                                                                  GskInsertFunc           insert_func);
 void                    gsk_diff_settings_free                  (GskDiffSettings        *settings);
+void                    gsk_diff_settings_set_allow_abort       (GskDiffSettings        *settings,
+                                                                 gboolean                allow_abort);
 
-void                    gsk_diff                                (gconstpointer          *elem1,
+GskDiffResult           gsk_diff                                (gconstpointer          *elem1,
                                                                  gsize                   n1,
                                                                  gconstpointer          *elem2,
                                                                  gsize                   n2,
index d1dbfae12f8c81dee374947ad5aa43daadc59cc5..59681c888cbf8b7af7db692480df3b15142a9d2c 100644 (file)
@@ -2193,6 +2193,7 @@ gsk_container_node_get_diff_settings (void)
                                     gsk_container_node_keep_func,
                                     gsk_container_node_change_func,
                                     gsk_container_node_change_func);
+  gsk_diff_settings_set_allow_abort (settings, TRUE);
 
   return settings;
 }
@@ -2205,12 +2206,15 @@ gsk_container_node_diff (GskRenderNode  *node1,
   GskContainerNode *self1 = (GskContainerNode *) node1;
   GskContainerNode *self2 = (GskContainerNode *) node2;
 
-  gsk_diff ((gconstpointer *) self1->children,
-            self1->n_children,
-            (gconstpointer *) self2->children,
-            self2->n_children,
-            gsk_container_node_get_diff_settings (),
-            region);
+  if (gsk_diff ((gconstpointer *) self1->children,
+                self1->n_children,
+                (gconstpointer *) self2->children,
+                self2->n_children,
+                gsk_container_node_get_diff_settings (),
+                region) == GSK_DIFF_OK)
+    return;
+
+  gsk_render_node_diff_impossible (node1, node2, region);
 }
 
 static void